/**
 * @author Kristian Mandrup
 * @date May 25, 2009
 * @version 0.1
 * 
 * m3gen :: Base functions
 * 
 * Utility functions needed by all components of m3gen
 */ 

// Global constants
m3gen.Base.INSTANCE = m3gen.constants.nodeType.INSTANCE;
m3gen.Base.REFERENCE = m3gen.constants.nodeType.REFERENCE;

// Utility functions
m3gen.Base.prototype.getTheContext 	= m3gen.util.getTheContext;
m3gen.Base.prototype.isEmptyObj 	= m3gen.util.isEmptyObj;
m3gen.Base.prototype.isArray 		= m3gen.util.isArray;
m3gen.Base.prototype.isFunction 	= m3gen.util.isFunction;
m3gen.Base.prototype.isString		= m3gen.util.isString;
m3gen.Base.prototype.getUniqueArray = m3gen.util.getUniqueArray;
m3gen.Base.prototype.flatten 		= m3gen.util.flatten;
m3gen.Base.prototype.oc 			= m3gen.util.oc;
m3gen.Base.prototype.convertToId 	= m3gen.util.convertToId;

m3gen.Base.prototype.concatNodeObjArrays 		= m3gen.util.concatNodeObjArrays;
m3gen.Base.prototype.concatJsTreeNodeArrays 	= m3gen.util.concatJsTreeNodeArrays;
m3gen.Base.prototype.concatArrays 				= m3gen.util.concatArrays;

/**
 * initialize the jsTreeModel Generator
 * @param {Object} modelsObj
 */
m3gen.Base.prototype.initializeGenerator = function(modelsObj){
	// set global exec state
	this.setGlobalExecState({
		objTypeCounter: {}
	});	
	
	var instanceModel = null;
	var generatorModel = null;
	
	// test if argument is simply a generator model
	if (this.isValidRuleSetConfiguration(modelsObj.ruleSetConfiguration)) {
		generatorModel = modelsObj;
	}
	else {
		// set instance model to parse
		instanceModel = modelsObj.jsonInstanceModel;
		
		// set generator model to use for parsing/generation	
		generatorModel = modelsObj.generatorModel;
	}
	this.setGeneratorModel(generatorModel);
	this.setInstanceModel(instanceModel);
	
	// initialize global idVisitedList used for this model generation session
	this.setVisitedList([]);
}
/**
 * Set options of generator and get the initial jsonInstanceModel
 * 
 * @param 	{Object} options
 * @return 	{Object} jsonInstanceModel
 */
m3gen.Base.prototype.getInitialInstanceModel = function(options) {
	if (this.isValidOptions(options)) {			
		this.setInstanceModelOptions(options);						
		this.setGeneratorModel(options.generatorModel);
		this.setNodeStateList(options.nodeStateList);
	}
	// get instance model
	var jsonInstanceModel = this.getInstanceModel();
	if (!jsonInstanceModel) {
		throw m3gen.exception.MissingJsonInstanceModel;
	}
	return jsonInstanceModel;		
}
/**
 * 
 * @param {Object} className
 */
m3gen.Base.prototype.setClassName = function(className) {
	this.className = className;
}

/**
 * 
 */
m3gen.Base.prototype.getClassName = function() {
	return this.className;
}


/**
 * 
 * @param {Object} handlerName
 */
m3gen.Base.prototype.handleBegin = function(handlerName){
	return this.handle('onBegin' + handlerName);	
}

/**
 * 
 * @param {Object} handlerName
 */
m3gen.Base.prototype.handleEnd = function(handlerName){
	return this.handle('onEnd' + handlerName);	
}

/**
 * 
 * @param {Object} handlerName
 */
m3gen.Base.prototype.handle = function(handlerName) {
	var context = this.getContext(this);
	context.eventController.handle(handlerName, context);
	return context;
} 

/**
 * Use to run json content selection functions!
 * 
 * @param {Object} selectFun
 * @param {Object} funName
 * @param {Object} options
 */
m3gen.Base.prototype.doSelect = function(selectFun, funName, options) {
	var context = this.handle('onBeginSelect' + funName);
	var result = selectFun(this.getActiveObj(), context, options);
	this.handle('onEndSelect' + funName);
	return result;
}

// Misc

m3gen.Base.prototype.generateIdObject = function() {
	var id = this.generateUniqueId();
	return {id: id, unique_id: id};
} 

/**
 * Generate a unique ID for an object
 */
m3gen.Base.prototype.generateUniqueId = function(){
	var objType = this.getActiveObjType();
	return objType + '_' + this.getObjTypeCounter(objType);
}
// Builder

/**
 * Get the state to show for a branchRule
 * @param {Object} state
 */
m3gen.Base.prototype.getStateOfBranchRule = function(branchTypeRule_state) {
	return branchTypeRule_state || this.getDefaultState();
}

/**
 * Get useUniqueId
 */
m3gen.Base.prototype.getUseUniqueId = function() {
	return this.getActiveRuleSet() || this.getRuleSetConfiguration().useUniqueId || false;
}

/**
 * Get pathMethod
 */
m3gen.Base.prototype.getPathMethod = function() {
	return this.getActiveRuleSet().pathMethod || this.getRuleSetConfiguration().pathMethod;
}

/**
 * Get the active Json PathFinder method
 */
m3gen.Base.prototype.getActiveJsonPathFinder = function() {
	var method = this.getPathMethod();
	var jsonPathFinder = null;
	if (this.isValidString(method)) {
		jsonPathFinder = m3gen.pathFinderSettings.methods[method];
		if (this.isFunction(jsonPathFinder))
			return jsonPathFinder;
		else console.log('getActiveJsonPathFinder: invalid jsonPathFinder (not a function)');					
	}
	else 
		console.log('getActiveJsonPathFinder: invalid method name');			
	return null;
}

// Exception handlers

/**
 * 
 * @param {Object} eventController
 */
m3gen.Base.prototype.setEventController = function(eventController){
	this.eventController = eventController || m3gen.eventController;
}

/**
 * 
 */
m3gen.Base.prototype.getEventController = function() {
	return this.eventController;
}

/**
 * 
 * @param {Object} mainExceptionHandler
 */
m3gen.Base.prototype.setExceptionHandler = function(exceptionHandler){	
	this.mainExceptionHandler = this.getObjDef(exceptionHandler, m3gen.exception.handler);
}

/**
 * 
 */
m3gen.Base.prototype.getExceptionHandler = function() {
	return this.mainExceptionHandler;
}

m3gen.Base.prototype.callExceptionHandler = function(e) {
	var handler = this.getExceptionHandler();
	handler(e);
}

// Create Options

/**
 * Get CreateOptions
 */
m3gen.Base.prototype.getCreateOptions = function() {
	return this.createOptions;
}

/**
 * Set CreateOptions
 * @param {Object} createOptions
 */
m3gen.Base.prototype.setCreateOptions = function(createOptions){
	var constructors = null;
	if (this.isValidObj(createOptions)) {
		constructors = createOptions.constructors || createOptions
	}	
	this.createOptions = this.getConstructors(constructors);
}

/**
 * Default constructors for all m3gen components
 * 
 * TODO: Capitalize constructor names
 */
m3gen.Base.prototype.getConstructors = function(constructors) {
	var c = this.getAnObj(constructors);
	var constructors = {
		JsonObjParser: this.getObjDef(c.JSONObjParser, m3gen.JSONObjParser),
		ChildrenParser: this.getObjDef(c.ChildrenParser, m3gen.ChildrenParser),
				
		JsTreeNodeBuilder: this.getObjDef(c.JsTreeNodeBuilder,  m3gen.JsTreeNodeBuilder),
		
		AttributesBuilder: this.getObjDef(c.AttributesBuilder, m3gen.jsTreeNode.AttributesBuilder),
		
		JsTreeBranchBuilder: this.getObjDef(c.JsTreeBranchBuilder, m3gen.JsTreeBranchBuilder),
				
		NodeObjBuilder: this.getObjDef(c.NodeObjBuilder, m3gen.NodeObjBuilder),
		NodeObjBranchBuilder: this.getObjDef(c.NodeObjBranchBuilder, m3gen.NodeObjBranchBuilder)
						
	}
	return constructors;
}

/**
 * Utility function that could be used by m3gen.Base.prototype.getConstructors
 * 
 * @param {Object} customConstructor
 * @param {Object} defaultConstructor
 */
m3gen.Base.prototype.selectConstructor = function(customConstructor, defaultConstructor) {
	if (this.isValidObj(customConstructor)) {
		return customConstructor;
	}
	return defaultConstructor;
}	

// create instance from constructor

m3gen.Base.prototype.getInstance = function(constructor) {
	// Create instance of constructor and initialize it
	return new constructor(this.getInitializeOptions());	
}

// retrieve constructors



// parsers
/**
 * Get JsonObjParser constructor
 */
m3gen.Base.prototype.getJsonObjParser = function(){
	var co = this.getCreateOptions();
	return co.JsonObjParser;
}

/**
 * Create JsonObjParser instance
 * 
 * @return JsonObjParser instance
 */
m3gen.Base.prototype.getJsonObjParserInstance = function() {	
	return this.getInstance(this.getJsonObjParser());
}

/**
 * Get ChildrenParser constructor
 */
m3gen.Base.prototype.getChildrenParser = function(){
	return this.getCreateOptions().ChildrenParser;
}

/**
 * Create ChildrenParser instance
 * 
 * @return ChildrenParser instance
 */
m3gen.Base.prototype.getChildrenParserInstance = function() {	
	return this.getInstance(this.getChildrenParser());
}

// jsTree node builders

/**
 * Get JsTreeNodeContentBuilder constructor
 */
m3gen.Base.prototype.getJsTreeNodeContentBuilder = function(){
	return this.getCreateOptions().JsTreeNodeContentBuilder;
}

/**
 * Create JsTreeNodeContentBuilder instance
 * 
 * @return JsTreeNodeContentBuilder instance
 */
m3gen.Base.prototype.getJsTreeNodeContentBuilderInstance = function() {	
	return this.getInstance(this.getJsTreeNodeContentBuilder());
}

/**
 * Get JsTreeNodeBuilder constructor
 */
m3gen.Base.prototype.getJsTreeNodeBuilder = function(){
	return this.getCreateOptions().JsTreeNodeBuilder;
}

/**
 * Create JsTreeNodeBuilder instance
 * 
 * @return JsTreeNodeBuilder instance
 */
m3gen.Base.prototype.getJsTreeNodeBuilderInstance = function() {	
	return this.getInstance(this.getJsTreeNodeBuilder());
}

/**
 * Get JsTreeBranchBuilder constructor
 * 
 * @return JsTreeBranchBuilder constructor
 */
m3gen.Base.prototype.getJsTreeBranchBuilder = function(){
	return this.getCreateOptions().JsTreeBranchBuilder;
}

/**
 * Create JsTreeBranchBuilder instance
 * 
 * @return JsTreeBranchBuilder instance
 */
m3gen.Base.prototype.getJsTreeBranchBuilderInstance = function() {	
	return this.getInstance(this.getJsTreeBranchBuilder());
}

// nodeObj builders

/**
 * Get NodeObjBuilder constructor
 */
m3gen.Base.prototype.getNodeObjBuilder = function(){
	return this.getCreateOptions().NodeObjBuilder;
}

/**
 * Create NodeObjBuilder instance
 * 
 * @return NodeObjBuilder instance
 */
m3gen.Base.prototype.getNodeObjBuilderInstance = function() {	
	return this.getInstance(this.getNodeObjBuilder());
}

/**
 * Get NodeObjBranchBuilder constructor
 */
m3gen.Base.prototype.getNodeObjBranchBuilder = function(){
	var co = this.getCreateOptions();
	return co.NodeObjBranchBuilder;
}

/**
 * Create NodeObjBranchBuilder instance
 * 
 * @return NodeObjBranchBuilder instance
 */
m3gen.Base.prototype.getNodeObjBranchBuilderInstance = function() {	
	return this.getInstance(this.getNodeObjBranchBuilder());
}

// JsTree Node content builders	

/**
 * Get AttributesBuilder constructor
 */
m3gen.Base.prototype.getAttributesBuilder = function(){
	return this.getCreateOptions().AttributesBuilder;
}

/**
 * Create AttributesBuilder instance
 * 
 * @return AttributesBuilder instance
 */
m3gen.Base.prototype.getAttributesBuilderInstance = function() {
	return this.getInstance(this.getAttributesBuilder());
}

/**
 * Get ChildrenBuilder constructor
 */
m3gen.Base.prototype.getChildrenBuilder = function(){
	return m3gen.jsTreeNode.ChildrenBuilder;
}

/**
 * Create ChildrenBuilder instance
 * 
 * @return ChildrenBuilder instance
 */
m3gen.Base.prototype.getChildrenBuilderInstance = function() {
	return this.getInstance(this.getChildrenBuilder());
}

/**
 * Get DataBuilder constructor
 */
m3gen.Base.prototype.getDataBuilder = function(){
	return m3gen.jsTreeNode.DataBuilder;
}

/**
 * Create DataBuilder instance
 * 
 * @return DataBuilder instance
 */
m3gen.Base.prototype.getDataBuilderInstance = function() {
	return this.getInstance(this.getDataBuilder());
}

/**
 * Get StateBuilder constructor
 */
m3gen.Base.prototype.getStateBuilder = function(){
	return m3gen.jsTreeNode.StateBuilder;
}

/**
 * Create StateBuilder instance
 * 
 * @return StateBuilder instance
 */
m3gen.Base.prototype.getStateBuilderInstance = function() {
	return this.getInstance(this.getStateBuilder());
}

/**
 * Get MetaDataBuilder constructor
 */
m3gen.Base.prototype.getMetaDataBuilder = function(){
	return m3gen.jsTreeNode.MetaDataBuilder;
}

/**
 * Create MetaDataBuilder instance
 * 
 * @return MetaDataBuilder instance
 */
m3gen.Base.prototype.getMetaDataBuilderInstance = function() {
	return this.getInstance(this.getMetaDataBuilder());
}

// resolve content

/**
 * Get ResolvedContentBuilder constructor
 */
m3gen.Base.prototype.getResolvedContentBuilder = function(){
	return m3gen.ResolvedContentBuilder;
}

/**
 * Create ResolvedContentBuilder instance
 * 
 * @return ResolvedContentBuilder instance
 */
m3gen.Base.prototype.getResolvedContentBuilderInstance = function() {
	return this.getInstance(this.getResolvedContentBuilder());
}


// intialize options

m3gen.Base.prototype.getInitializeOptions = function() {
	return {
		constructors: this.getCreateOptions(),
		globalExecState: this.getGlobalExecState(),
	};
}


m3gen.Base.prototype.getContext = function(callerObj) {
	return {
		eventController: this.getEventController(),
		exceptionHandler: this.getExceptionHandler(),
		globalExecState: this.getGlobalExecState(),
		callerObj: callerObj
	}
}	

// Global execute state

/**
 * Set the Global Execute State
 * 
 * The Global execution state consist of the following
 * - objTypeCounters and their state (fx objTypeCounter[person] = 5
 * - ruleSetConfiguration
 * - visitedList (which nodes have we visited)
 * - nodeStateList (in what state should specific nodes be displayed)
 * 
 * These should never be cleared within a Generator session
 * 
 * The Global execution state can also contain the following
 * - activeRuleSet
 * - activeObj
 * - objType
 * 
 * These must always be cleared (using clearGlobalExecState) before each call to jsonObjParser.execute() 
 * and be reset to new values in the start of this method as the jsonObj is parsed
 */
m3gen.Base.prototype.setGlobalExecState = function(globalExecState){
	if (this.isValidGlobalExecState(globalExecState)) {
		this.globalExecState = globalExecState;
		if (globalExecState.ruleSetConfiguration)
			this.setRuleSetConfiguration(globalExecState.ruleSetConfiguration);
		if (globalExecState.visitedList)
			this.setVisitedList(globalExecState.visitedList);
		if (globalExecState.nodeStateList)
			this.setNodeStateList(globalExecState.nodeStateList);		

		/*	
		if (globalExecState.activeRuleSet)
			this.setActiveRuleSet(globalExecState.activeRuleSet);		
		*/
		if (globalExecState.activeObj)
			this.setActiveObj(globalExecState.activeObj);		
		/*	
		if (globalExecState.objType)
			this.setActiveObjType(globalExecState.objType);		
		*/	

			
		return globalExecState;
	} // else throw InvalidGlobalExecState;
}

/**
 * Clear the parts of GlobalExecState that should be reinitialized in each parse session
 * Just to ensure we do NOT carry around and use parse state from a previos parse session!
 * 
 * This should be called as part of initializing a jsonParseObj (in the JsonParseObj constructor or init method)
 */
m3gen.Base.prototype.clearGlobalExecState = function() {
	this.globalExecState.activeRuleSet = null;
	this.globalExecState.activeObj = null;
	this.globalExecState.objType = null;
}

/**
 * Get global Execution state
 */
m3gen.Base.prototype.getGlobalExecState = function(){
	return this.globalExecState;
}

// ActiveRuleSet

 /**
 * Get the active ruleset
 * @param {Object} objType
 */
m3gen.Base.prototype.getActiveRuleSet = function() {
	return this.activeRuleSet;
}

/**
 * Set the active ruleset 
 * @param {Object} ruleSet
 */
m3gen.Base.prototype.setActiveRuleSet = function(ruleSet) {
	if (this.isValidRuleSet(ruleSet)) {
		this.activeRuleSet = ruleSet;
		this.getGlobalExecState().activeRuleSet = ruleSet;
		return ruleSet;
	} else throw m3gen.exception.InvalidRuleSet;
}

m3gen.Base.prototype.setActiveRuleSetByObjType = function(objType){
	this.setActiveRuleSet(this.getRuleSet(objType));
}

// RuleSet

/**
 * Get the ruleset for an objType
 * @param {Object} objType
 */
m3gen.Base.prototype.getRuleSet = function(objType) {
	var ruleSet = this.getRuleSetConfiguration().ruleSets[objType];;
	if (ruleSet) 
		return ruleSet;
	else {
		m3gen.log('Missing a matching ruleSet for objType encountered:' + objType);
	}
}

/**
 * Retrieve the matching ruleSet from RuleSetConfiguration for a particular jsonObj
 * @param {Object} jsonObj
 */
m3gen.Base.prototype.getRuleSetForObject = function(jsonObj){
	var objType = this.getObjType(jsonObj);
	return this.getRuleSet(objType);
}

// ActiveObj

/**
 * Get the active jsonObj being parsed
 * @param {Object} objType
 */
m3gen.Base.prototype.getActiveObj = function() {
	return this.activeObj;
}

/**
 * Set the active jsonObj being parsed
 * @param {Object} jsonObj
 */
m3gen.Base.prototype.setActiveObj = function(jsonObj) {
	if (this.isValidObj(jsonObj)) {
		this.activeObj = jsonObj;
		this.getGlobalExecState().activeObj = jsonObj;		
		this.setActiveObjTypeByObj(jsonObj);
		return jsonObj;
	} else throw m3gen.exception.InvalidJsonObject;
}

// RuleSetConfiguration

/**
 * Get RuleSetConfiguration
 */
m3gen.Base.prototype.getRuleSetConfiguration = function() {
	return this.ruleSetConfiguration;
}

/**
 * 
 * @param {Object} ruleSetConfiguration
 */
m3gen.Base.prototype.setRuleSetConfiguration = function(ruleSetConfiguration){
	if (this.isValidRuleSetConfiguration(ruleSetConfiguration)) {
		this.ruleSetConfiguration = ruleSetConfiguration;
		this.getGlobalExecState().ruleSetConfiguration = ruleSetConfiguration;			
		return this.ruleSetConfiguration;
	} else throw m3gen.exception.InvalidRuleSetConfiguration;
}

// ObjType

/**
 * Get the objType for a jsonObj
 * @param {Object} jsonObj
 */
m3gen.Base.prototype.getObjType = function(jsonObj){
	var ruleSetConfig = this.getRuleSetConfiguration();
	var objType = ruleSetConfig.selectObjType(jsonObj);
	return objType;
}

// Generator model

/**
 * Get the ruleSetConfiguration which the JsTreeModelGenerator was initialized with
 */
m3gen.Base.prototype.setGeneratorModel = function(generatorModel) {
	if (this.isValidGeneratorModel(generatorModel)) {
		this.generatorModel = generatorModel;
		this.getGlobalExecState().generatorModel = generatorModel;			
		this.setRuleSetConfiguration(generatorModel.ruleSetConfiguration);
	}
}

/**
 * Get the genrator model
 */
m3gen.Base.prototype.getGeneratorModel = function() {
	return this.generatorModel;
}

// Instance Model

/**
 * Set instance model using options
 * @param {Object} options
 */
m3gen.Base.prototype.setInstanceModelOptions = function(options) {
	if (options) {
		if (options.instanceModel) 
			this.setInstanceModel(options.instanceModel);
		else if (options.jsonInstanceModel)
			this.setInstanceModel(options.jsonInstanceModel);
		else if (!options.generatorModel)
			this.setInstanceModel(options);
		else MissingJsonInstanceModel;
	} else throw m3gen.exception.InvalidOptions;
	return this.getInstanceModel();
}

/**
 * Set instance model
 * @param {Object} instanceModel
 */
m3gen.Base.prototype.setInstanceModel = function(instanceModel) {
	this.jsonInstanceModel = instanceModel;
	this.getGlobalExecState().jsonInstanceModel = instanceModel;	
}

/**
 * Get instance model
 */
m3gen.Base.prototype.getInstanceModel = function(){
	return this.jsonInstanceModel;
}

// Default state

/**
 * Get the default state
 * @param {Object} ruleSet
 */
m3gen.Base.prototype.getDefaultState = function(ruleSet){
	var _defaultState = null;
	if (this.isValidRuleSet(ruleSet)) {
		_defaultState = ruleSet.defaultState;
	}	
	return _defaultState || this.getActiveRuleSet().defaultState || this.getRuleSetConfiguration().defaultState || 'closed';
}

// Use unique Id


/**
 * Determine if use unique ID
 * @param {Object} ruleSet
 */
m3gen.Base.prototype.getUseUniqueId = function(ruleSet){
	var _useUniqueId = null;
	if (this.isValidRuleSet(ruleSet)) {
		_useUniqueId = ruleSet.useUniqueId;
	}		
	return _useUniqueId || this.getActiveRuleSet().useUniqueId || this.getRuleSetConfiguration().useUniqueId || false;
}



// IconsPath

/**
 * Create and return the full icons path
 */
m3gen.Base.prototype.getFullIconsPath = function(icon) {
	return this.getIconsPath() + '/' + icon;
}

/**
 * Get iconsPath
 */
m3gen.Base.prototype.getIconsPath = function() {
	return this.getActiveRuleSet().iconsPath || this.getRuleSetConfiguration().iconsPath || '';
}

// Default state

/**
 * Get default state
 */
m3gen.Base.prototype.getDefaultState = function() {
	return this.getActiveRuleSet().defaultState || this.getRuleSetConfiguration().defaultState || 'closed';
}

// objType Counter

/**
 * Get a counter for a specific type of object
 * @param {Object} objType
 */
m3gen.Base.prototype.getObjTypeCounter = function(objType){
	var _objType = null;
	if (this.isValidObjType(objType)) {
		_objType = objType;
	}	
	_objType = _objType || this.getActiveObjType();
	return this.getGlobalExecState().objTypeCounter[_objType] || 0;
}

/**
 * Set the active counter using objType
 * - reference in GlobalExecState
 * 
 * @param {Object} objType
 */
m3gen.Base.prototype.setActiveObjTypeCounter = function(objType){
	var _objType = objType || this.getActiveObjType();
	if (this.isValidObjType(_objType)) {
		var counter = this.getObjTypeCounter(_objType);
		this.getGlobalExecState().activeCounter = counter;				
		this.activeCounter = counter
	}
}

/**
 * Get active ObjType counter
 */
m3gen.Base.prototype.getActiveObjTypeCounter = function(){
	return this.activeCounter;
}

// Active objType

/**
 * Get the active objType
 */
m3gen.Base.prototype.getActiveObjType = function(){
	return this.objType;
}

/**
 * Get the active objType
 * - reference in GlobalExecState
 * 
 * @param {Object} objType
 */
m3gen.Base.prototype.setActiveObjType = function(objType){
	if (this.isValidObjType(objType)) {
		this.objType = objType;
		this.getGlobalExecState().objType = objType;
		this.setActiveRuleSetByObjType(objType);
		this.setActiveObjTypeCounter(objType);
		return objType;
	} else throw m3gen.exception.InvalidObjType;
}

m3gen.Base.prototype.setActiveObjTypeByObj = function(jsonObj){
	this.setActiveObjType(this.getObjType(jsonObj));	
}

// Id visited list

/**
 * Set the Id visited list
 * - reference in GlobalExecState
 * 
 * @param {Object} idVisitedList
 */
m3gen.Base.prototype.setVisitedList = function(visitedList){
	this.visitedList = visitedList;
	this.getGlobalExecState().visitedList = visitedList;
	return visitedList;
}

/**
 * Get the list of ids already visited
 */
m3gen.Base.prototype.getVisitedList = function() {
	return this.visitedList;
}

/**
 * Check if id exists in the visited idList
 * @param {Object} id
 */
m3gen.Base.prototype.isIdInVisitedList = function(id){
	return id in this.oc(this.getVisitedList());
}

/**
 * Add Id to visited list
 * @param {Object} id
 */
m3gen.Base.prototype.addIdToVisitedList = function(id){
	var visitedList = this.getVisitedList();
	if (this.isString(id)) 
		visitedList.push(id);
	else {
		console.log('addIdToVisitedList: not a valid id');
	}
}

/**
 * Add Id to Visited list if it is an instance
 * @param {Object} id
 */
m3gen.Base.prototype.addIdToVisitedListConditional = function(id){
	var nodeType = this.getNodeType(id);
	if (nodeType == this.INSTANCE) {
		this.addIdToVisitedList(id);
	}
}
// node state list

/**
 * Set node state list 
 * - reference in GlobalExecState
 * 
 * @param {Object} nodeStateList
 */
m3gen.Base.prototype.setNodeStateList = function(nodeStateList) {
	if (!this.isValidObj(nodeStateList))
		nodeStateList = {open: [], closed: []};
	this.nodeStateList = nodeStateList;
	this.getGlobalExecState().nodeStateList = nodeStateList;
	return nodeStateList;	
}

/**
 * Get the model name
 */
m3gen.Base.prototype.getNodeStateList = function() {
	return this.nodeStateList;
}

// model name

/**
 * Set the model name
 * @param {Object} name
 */
m3gen.Base.prototype.setModelName = function(name) {
	this.modelName = name;
	return name;	
}

/**
 * Get the model name
 */
m3gen.Base.prototype.getModelName = function() {
	return this.modelName;
}

// Active functions

/**
 * Get the active functions of the active ruleset used for resolving content of the active jsonObj
 */
m3gen.Base.prototype.getActiveFunctions = function() {
	var activeRuleSet = this.getActiveRuleSet();
	return activeRuleSet.functions;
}

m3gen.Base.prototype.getActiveFunctionsByRuleset = function(ruleSet){
	var activeFunctions = this.getActiveRuleSet();
	if (ruleSet) 
		activeFunctions = ruleSet.functions || activeFunctions;
	return activeFunctions
}

/**
 * Determine if nodeType is a reference
 * @param {Object} nodeType
 */
m3gen.Base.prototype.isReference = function(nodeType){
	return !(nodeType == this.REFERENCE)
}

/**
 * Determine if nodeType is an instance
 * @param {Object} nodeType
 */
m3gen.Base.prototype.isInstance = function(nodeType){
	return !(nodeType == this.INSTANCE)
}

/**
 * Get the node type for
 * @param {Object} objType
 */
m3gen.Base.prototype.getNodeType = function(id){
	// id this id has already been encountered before (is in idList)
	// this node must be treated as a reference! (to avoid endless cycle)	
	var nodeType = this.INSTANCE;	
	if (this.isIdInVisitedList(id)) {
		nodeType = this.REFERENCE;
	}
	return nodeType;
}

/**
 * TODO: Maybe the whole ID business should be refactored to be more simple!
 * @param {Object} nodeObj
 */
m3gen.Base.prototype.getIdFromNodeObj = function (nodeObj) {
	if (this.isValidObj(nodeObj)) {
		var id = nodeObj.id;
		if (this.isValidObj(id)) {
			if (this.isString(id))
				return id;
			else {
				return id.id;
			}	
		}
	}
	console.log('getIdFromNodeObj: invalid id');
}

m3gen.Base.prototype.getUniqueIdFromNodeObj = function (nodeObj) {
	if (this.isValidObj(nodeObj)) {
		var id = nodeObj.id;
		if (this.isValidObj(id)) {
			if (id.uniqueId) 
				return id.uniqueId;
			else return id.id || id;	
		}
	}
	console.log('getIdFromNodeObj: invalid id');
}

/**
 * A valid jsTree node must have an 'attributes' key with an 'id' key assigned a non-empty string identifier
 * @param {Object} jsTreeNode
 */
m3gen.Base.prototype.isValidJsTreeNode = function(jsTreeNode) {
	String.prototype.trim = function () {
		return this.replace(/^\s*|\s*$/,"");
	}	
	if (this.isValidObj(jsTreeNode)) {
		if (jsTreeNode.attributes) {
			if (jsTreeNode.attributes.id) {
				// TODO: ID should not be an object!
				var id = jsTreeNode.attributes.id;
				if (typeof id == 'string') {
					var _id = id.trim();
					return id.trim() != '';
				}
				else {
					console.log('isValidJsTreeNode: jsTreeNode attributes.id should be a string');
					// console.log(id);
				}
			} else console.log('isValidJsTreeNode: jsTreeNode missing attributes.id');
		} else console.log('isValidJsTreeNode: jsTreeNode missing attributes');
	} else console.log('isValidJsTreeNode: jsTreeNode is invalid');
	return false;
}

// Node obj

/**
 * Set children to a nodeObj
 * @param {Object} nodeObj
 * @param {Object} children
 */	
m3gen.Base.prototype.putChildrenOnNodeObj = function(nodeObj, children) {
	if (this.isNotEmptyArray(children))
		nodeObj.children = children;
	return nodeObj;
}

m3gen.Base.prototype.addChildren = function(arr, children) {
	if (this.isNotEmptyArray(children))
		this.concatArrays(arr, children);
	return arr;
}

m3gen.Base.prototype.addNodeChildren = function(arr, children) {
	if (this.isNotEmptyArray(children))
		this.concatArrays(arr, children, this.isValidNodeObj);
	return arr;
}

m3gen.Base.prototype.setLanguageModeOn = function(languageModeOn) {
	this.languageModeOn = languageModeOn;
}

m3gen.Base.prototype.getLanguageModeOn = function() {
	return this.languageModeOn;
}

m3gen.Base.prototype.setEmptyBranchesModeOn = function(emptyBranchesModeOn) {
	this.emptyBranchesModeOn = emptyBranchesModeOn;
}

m3gen.Base.prototype.getIncludeEmptyBranchesModeOn = function() {
	return this.emptyBranchesModeOn;
}


// resolve json Obj using selector

m3gen.Base.prototype.resolveObjWithSelector = function(jsonObj, childSelector) {
	var jsonPathFinder = this.getActiveJsonPathFinder();
	if (this.isFunction(jsonPathFinder)) {
		var childrenFound = jsonPathFinder(jsonObj, childSelector);
		return childrenFound;
	} else {
		console.log('jsonPathFinder not a function');
		return null;
	}
}


m3gen.Base.prototype.isNonEmptyBranchNodeObj = function(nodeObj) {
	return nodeObj.isBranch && nodeObj.children.length > 0;
}

m3gen.Base.prototype.isEmptyBranchNodeObj = function(nodeObj) {
	return nodeObj.isBranch && this.isEmptyArray(nodeObj.children);
}

// Is valid functions
m3gen.Base.prototype.getObjDef = m3gen.util.getObjDef;
m3gen.Base.prototype.validObj = m3gen.util.validObj;
m3gen.Base.prototype.getAnObj = m3gen.util.getAnObj;
m3gen.Base.prototype.isValidGlobalExecState = m3gen.util.isValidGlobalExecState;
m3gen.Base.prototype.isValidGeneratorModel = m3gen.util.isValidGeneratorModel;
m3gen.Base.prototype.isValidOptions = m3gen.util.isValidOptions;
m3gen.Base.prototype.isValidRuleSetConfiguration = m3gen.util.isValidRuleSetConfiguration;
m3gen.Base.prototype.isValidNodeObj = m3gen.util.isValidNodeObj;
m3gen.Base.prototype.isValidJsTreeNode = m3gen.util.isValidJsTreeNode;
m3gen.Base.prototype.isNotEmptyArray = m3gen.util.isNotEmptyArray;
m3gen.Base.prototype.isEmptyArray = m3gen.util.isEmptyArray;
m3gen.Base.prototype.isValidObj = m3gen.util.isValidObj;
m3gen.Base.prototype.isValidString = m3gen.util.isValidString;
m3gen.Base.prototype.isValidRuleSet = m3gen.util.isValidRuleSet;
m3gen.Base.prototype.isValidObjType = m3gen.util.isValidObjType;

